#pragma once

//QtOpenGl support
#include <QtOpenGL>

//Lemon graph files
#include <lemon/list_graph.h>
#include <lemon/dijkstra.h>
#include <lemon/connectivity.h>

//std map
#include <map>
#include <ctime>

//CGMesh definition
#include "core/engine/mesh_definition.h"

//AVL trees
#include "AVL.h"
#include "auxiliartypes.h"

#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
#include <Eigen/Sparse>

/**
 * Class Augmented Silhouette (ASilhouette)
 **/
class ASilhouette {

public:
	//the AVL tree is shared with all the silhouette in order to avoid to repeat the same operation over and over
	ASilhouette(std::vector<CGMesh*>& m, int index, CGPoint p, AVLTree<EdgePair>& t);
	//add vertex to the silhouette
	void addVertex(int index);
	//add edge to the silhouette
	void addEdge(int from, int to, int index);
	//finalize the silhouette
	void finalize();
	//save silhouette to image file
	void save(QString filename, QString options, bool m = false, QColor color = Qt::black);
	//destroyer!
	~ASilhouette(void);

	//get POV
	CGPoint getPov();
	//get reference to the graph
	lemon::ListGraph* getGraph();
	//compute saliency
	void computeSaliency(QString clusteringType, QualityMeasure qual, Eigen::SparseVector<int>& saliency);

private:

	//meshlist reference
	std::vector<CGMesh*>& meshlist;
	//reference to the AVL tree
	AVLTree<EdgePair>& tree;
	//index of mesh
	int mesh;
	//point of view
	CGPoint pov;

	//min and max deformation values
    double minquality;
    double maxquality;

	//undirected graph representing the silhouette
	lemon::ListGraph graph;	
	lemon::ListGraph copygraph;

	//correspondence maps
	std::map<int, lemon::ListGraph::Node> vertexToNode;
	std::map<lemon::ListGraph::Node, int> nodeToVertex;
	std::map<int, lemon::ListGraph::Edge> edgeToArc;
	std::map<lemon::ListGraph::Edge, int> arcToEdge;

	//quality for nodes (deformation of mesh vertices)
	lemon::ListGraph::NodeMap<double>		*deformation;
	lemon::ListGraph::NodeMap<VertexType>	*significant;

	//cluster and node-clustes map
        std::vector<std::set<int> > clusters;
	std::map<int, int> vertexToCluster;

	//vertex clustering (significant vs non-significant)
	void vertexClustering(QString type, double ts = 0.0);

	//analyzie edgepair
	double analyzeEdgePair( EdgePair ep, QualityMeasure qual );
	
	//create edge pair from node
	std::vector<EdgePair> getEdgePairs(lemon::ListGraph::Node n);

	//set deformation value
	void setDeformationValue( lemon::ListGraph::Node n, double value );

	//clustering
        void edgeClustering(std::vector<std::set<int> >& clusters, std::map<int, int>& vertexToCluster);
        void edgeClusteringAlternative(std::vector<std::set<int> >& clusters, std::map<int, int>& vertexToCluster);

	//compact cluster vector and relabel vertices
        void compactClusters(std::vector<std::set<int> >& clusters, std::map<int, int>& vertexToCluster);


};

